package com.chuangke.sinotrukbudget.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.druid.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.chuangke.admin.data.builder.DeptDataBuilder;
import com.chuangke.admin.dto.DataPermissionRequest;
import com.chuangke.admin.model.SysDataPermission;
import com.chuangke.admin.model.SysDept;
import com.chuangke.admin.service.SysDataPermissionService;
import com.chuangke.admin.service.SysDeptService;
import com.chuangke.core.data.builder.DataBuildConfig;
import com.chuangke.core.data.builder.DataBuilder;
import com.chuangke.core.exception.ChuangkeException;
import com.chuangke.core.id.IdManager;
import com.chuangke.core.page.CkPageQuery;
import com.chuangke.sinotrukbudget.data.builder.BudgetAccountBuilder;
import com.chuangke.sinotrukbudget.model.BudgetControlAccountDept;
import com.chuangke.sinotrukbudget.sdao.BudgetControlAccountDeptDaoService;
import com.chuangke.sinotrukbudget.service.BudgetControlAccountDeptService;

@Service
public class BudgetControlAccountDeptServiceImpl implements BudgetControlAccountDeptService {

	public static final String CACHE_NAME = "budget_control_account_dept";

	@Autowired
	private BudgetControlAccountDeptDaoService budgetControlAccountDeptDaoService;

	@Autowired
	private SysDataPermissionService sysDataPermissionService;

	@Autowired
	private SysDeptService sysDeptService;

	@Override
	public void save(BudgetControlAccountDept record) {
		((BudgetControlAccountDeptService) AopContext.currentProxy()).save(Arrays.asList(record));
	}

	@Override
	@Transactional(rollbackFor = Throwable.class)
	@CacheEvict(cacheNames = CACHE_NAME, key = "'" + CACHE_NAME + "'")
	public void save(List<BudgetControlAccountDept> records) {
		if (CollectionUtils.isEmpty(records)) {
			return;
		}

		records.forEach(record -> record.setId(IdManager.nextId()));

		QueryWrapper<BudgetControlAccountDept> queryWrapper = new QueryWrapper<>();
		queryWrapper.lambda().eq(BudgetControlAccountDept::getDeptId, records.get(0).getDeptId());
		List<BudgetControlAccountDept> list = budgetControlAccountDeptDaoService.list(queryWrapper);
		
		List<String> uniques = list.stream().map(bca -> bca.getDeptId()+"-"+bca.getControlAccountId()+"-"+bca.getControlDeptId()).collect(Collectors.toList()) ;
		
		records = records.stream().filter(bca -> !uniques.contains(bca.getDeptId()+"-"+bca.getControlAccountId()+"-"+bca.getControlDeptId())).collect(Collectors.toList()) ;
		
		list.addAll(records);

		Map<String, List<BudgetControlAccountDept>> groupMap = list.stream()
				.collect(Collectors.groupingBy(BudgetControlAccountDept::getControlAccountId));

		for (String accountId : groupMap.keySet()) {
			List<String> controlModeList = groupMap.get(accountId).stream().map(BudgetControlAccountDept::getControlMode).distinct()
					.collect(Collectors.toList());
			if (!CollectionUtils.isEmpty(controlModeList) && controlModeList.size() > 1) {
				throw new ChuangkeException(String.format("只能维护一种控制方式,科目[%s]维护了两种控制方式[%s]", accountId,String.join(",", controlModeList)));
			}
		}

		budgetControlAccountDeptDaoService.saveOrUpdateBatch(records);
	}

	@CacheEvict(cacheNames = CACHE_NAME, key = "'" + CACHE_NAME + "'")
	@Override
	public void delete(BudgetControlAccountDept record) {
		budgetControlAccountDeptDaoService.removeById(record);
	}

	@CacheEvict(cacheNames = CACHE_NAME, key = "'" + CACHE_NAME + "'")
	@Override
	public void delete(List<BudgetControlAccountDept> records) {
		List<String> idList = records.stream().map(BudgetControlAccountDept::getId).collect(Collectors.toList());
		budgetControlAccountDeptDaoService.removeBatchByIds(idList);
	}

	@CacheEvict(cacheNames = CACHE_NAME, key = "'" + CACHE_NAME + "'")
	@Override
	public void deleteByIds(List<String> ids) {
		budgetControlAccountDeptDaoService.removeByIds(ids);
	}

	@Cacheable(cacheNames = CACHE_NAME, key = "'" + CACHE_NAME + "'")
	@Override
	public Map<String, BudgetControlAccountDept> findMap() {
		List<BudgetControlAccountDept> list = budgetControlAccountDeptDaoService.list();
		return list.stream().collect(Collectors.toMap(BudgetControlAccountDept::getId, a -> a));
	}

	@Override
	public BudgetControlAccountDept findById(String id) {
		if (id == null) {
			return null;
		}

		Map<String, BudgetControlAccountDept> map = ((BudgetControlAccountDeptService) AopContext.currentProxy())
				.findMap();
		return map.get(id);
	}

	@Override
	public IPage<BudgetControlAccountDept> page(CkPageQuery page) {
		throw new ChuangkeException("不支持的方法");
	}

	/**
	 * 根据用户获取管控的数据
	 * 
	 * @param userId
	 * @return key:管控科目，value:管控单位
	 */
	@Override
	public Map<String, List<String>> getBudgetControlByUser(String userId) {
		if(StrUtil.isBlank(userId)) {
			return new HashMap<>();
		}
		
		DataPermissionRequest dpr = new DataPermissionRequest();
		dpr.setType(SysDataPermission.TYPE_USER_DUTY);
		dpr.setMaster1Id(userId);
		List<SysDataPermission> sdpList = sysDataPermissionService.find(dpr);

		if (CollectionUtils.isEmpty(sdpList)) {
			return new HashMap<>();
		}

		List<String> deptIdList = sdpList.stream().map(SysDataPermission::getDataId).collect(Collectors.toList());
		Map<String, BudgetControlAccountDept> map = ((BudgetControlAccountDeptService) AopContext.currentProxy())
				.findMap();

		List<BudgetControlAccountDept> bacList = map.values().stream()
				.filter(bac -> deptIdList.contains(bac.getDeptId())).collect(Collectors.toList());

		if (CollectionUtils.isEmpty(bacList)) {
			return new HashMap<>();
		}

		Map<String, List<BudgetControlAccountDept>> controlMap = bacList.stream()
				.collect(Collectors.groupingBy(BudgetControlAccountDept::getControlAccountId));

		Map<String, List<String>> result = new HashMap<>();
		for (String accountId : controlMap.keySet()) {
			List<BudgetControlAccountDept> controlList = controlMap.get(accountId);
			List<String> controlModeList = controlList.stream().map(BudgetControlAccountDept::getControlMode).distinct()
					.collect(Collectors.toList());
			if (!CollectionUtils.isEmpty(controlModeList) && controlModeList.size() > 1) {
				throw new ChuangkeException("配置出现问题，当前用户对应的归口部门，所对应的管控配置，同一个科目有两种管控方式");
			}

			List<String> controlDeptList = controlList.stream().map(BudgetControlAccountDept::getControlDeptId)
					.collect(Collectors.toList());
			List<String> bbDeptList = null;
			if (BudgetControlAccountDept.CONTROL_MODE_BH.equals(controlList.get(0).getControlMode())) {
				bbDeptList = controlDeptList;
			} else {
				bbDeptList = sysDeptService.findMap().values().stream()
						.filter(dept -> !controlDeptList.contains(dept.getId())).map(SysDept::getId)
						.collect(Collectors.toList());
			}
			result.put(accountId, bbDeptList);
		}

		return result;
	}

	@Override
	public List<BudgetControlAccountDept> findList() {
		Map<String, BudgetControlAccountDept> map = ((BudgetControlAccountDeptService) AopContext.currentProxy())
				.findMap();

		List<BudgetControlAccountDept> list = new ArrayList<>(map.values());
		if (!CollectionUtils.isEmpty(list)) {
			DataBuilder.of(list)
					.appendBuilder(new BudgetAccountBuilder(),
							new DataBuildConfig("controlAccountId", "ccontrolAccountName"))
					.appendBuilder(new DeptDataBuilder(), new DataBuildConfig("controlDeptId", "controlDeptName"))
					.build();
		}

		return new ArrayList<>(map.values());
	}

	@Override
	public List<BudgetControlAccountDept> findList(String deptId, List<String> controlAccountIdList) {
		List<BudgetControlAccountDept> allList = ((BudgetControlAccountDeptService) AopContext.currentProxy())
				.findList();
		if (CollectionUtils.isEmpty(allList)) {
			return new ArrayList<>();
		}

		if (StrUtil.isBlank(deptId)) {
			return new ArrayList<>();
		}

		if (CollectionUtils.isEmpty(controlAccountIdList)) {
			return allList.stream().filter(bcad -> bcad.getDeptId().equals(deptId)).collect(Collectors.toList());
		}

		return allList.stream().filter(
				bcad -> bcad.getDeptId().equals(deptId) && controlAccountIdList.contains(bcad.getControlAccountId()))
				.collect(Collectors.toList());
	}

}
